home *** CD-ROM | disk | FTP | other *** search
- From: tony@sdd.hp.com (Tony Parkhurst)
- Newsgroups: comp.sources.misc
- Subject: v19i014: pclcomp - HP-PCL graphics compression filter for printers., Part02/02
- Message-ID: <1991May2.172454.13851@sparky.IMD.Sterling.COM>
- Date: 2 May 91 17:24:54 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: dac0950d 1ef5dd6c 23039c04 276d9bb2
-
- Submitted-by: Tony Parkhurst <tony@sdd.hp.com>
- Posting-number: Volume 19, Issue 14
- Archive-name: pclcomp/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: pclcomp.c
- # Wrapped by kent@sparky on Thu May 2 12:17:56 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 2)."'
- if test -f 'pclcomp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'pclcomp.c'\"
- else
- echo shar: Extracting \"'pclcomp.c'\" \(52617 characters\)
- sed "s/^X//" >'pclcomp.c' <<'END_OF_FILE'
- X/*
- X** Pclcomp -- PCL compression filter.
- X**
- X** If you have any problems or errors to report, please send them to me:
- X**
- X** Tony Parkhurst
- X**
- X** Email address: tony@sdd.hp.com -or- hp-sdd!tony
- X**
- X** Please send a copy of the graphic file that is a problem, and the version
- X** of pclcomp you are using.
- X**
- X** All suggestions and requests are welcome.
- X*/
- X
- X/*
- X ***************************************************************************
- X *
- X * $Source: /disc/44/cgtriton/tony/filters/pclcomp/RCS/pclcomp.c,v $
- X * $Date: 91/04/30 09:41:24 $
- X * $Revision: 1.28 $
- X *
- X * Description: Compresses pcl graphics files.
- X *
- X * Author: Tony Parkhurst
- X * Created: 890427
- X * Language: C
- X *
- X * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved.
- X *
- X ***************************************************************************
- X */
- X
- X
- X/*
- X ***************************************************************************
- X *
- X * $Log: pclcomp.c,v $
- X * Revision 1.28 91/04/30 09:41:24 09:41:24 tony (Tony Parkhurst)
- X * Now puts stdin and stdout in binary mode for MSDOS.
- X * Changes courtesy of Mike Slomin.
- X * Changed usage message a bit.
- X *
- X * Revision 1.27 91/04/23 15:48:05 15:48:05 tony (Tony Parkhurst)
- X * Added handling of plus_sign in value fields.
- X *
- X * Revision 1.26 91/04/23 09:47:11 09:47:11 tony (Tony Parkhurst)
- X * Pass thru unknown modes.
- X *
- X * Revision 1.25 91/04/18 11:09:27 11:09:27 tony (Tony Parkhurst)
- X * Added parse for fractions in values (i.e. <esc>(s16.67H)
- X *
- X * Revision 1.24 91/04/10 14:16:30 14:16:30 tony (Tony Parkhurst)
- X * strips text and control codes between <esc>*rA and <esc>*rB w/ -s option
- X *
- X * Revision 1.23 91/04/05 14:53:25 14:53:25 tony (Tony Parkhurst)
- X * Added fixed for deskjet
- X * Also added a stripping feature.
- X *
- X * Revision 1.22 91/04/05 08:48:53 08:48:53 tony (Tony Parkhurst)
- X * Added some error checkin on output for MS-DOS users.
- X *
- X * Revision 1.21 91/04/04 12:53:32 12:53:32 tony (Tony Parkhurst)
- X * Replaced parser.
- X * Now handles combined escape sequences.
- X * Now handles downloads.
- X * Now combines mode changes with data.
- X *
- X * Revision 1.20 91/04/04 08:02:12 08:02:12 tony (Tony Parkhurst)
- X * Removed some test code.
- X *
- X * Revision 1.19 91/03/25 14:38:48 14:38:48 tony (Tony Parkhurst)
- X * Changed defaults.
- X *
- X * Revision 1.18 91/03/25 14:31:22 14:31:22 tony (Tony Parkhurst)
- X * Re-worked memory allocation stuff for funky input files.
- X *
- X * Revision 1.17 91/03/25 13:50:19 13:50:19 tony (Tony Parkhurst)
- X * Use command line args for file w/o -i or -o.
- X *
- X * Revision 1.16 91/03/04 14:23:15 14:23:15 tony (Tony Parkhurst)
- X * Fixed to allow ONLY mode 3 if the user really wants it.
- X *
- X * Revision 1.15 91/03/04 14:08:23 14:08:23 tony (Tony Parkhurst)
- X * Added an exit(0) at the end of main.
- X * fixed up some zerostrip stuff.
- X * made mode 3 the highest priority mode.
- X *
- X * Revision 1.14 91/02/20 13:57:27 13:57:27 tony (Tony Parkhurst)
- X * Changed priority a bit.
- X * Added some zerostripping for mode 2.
- X *
- X * Revision 1.13 91/02/06 15:31:00 15:31:00 tony (Tony Parkhurst)
- X * oops.
- X *
- X * Revision 1.12 91/02/06 14:41:28 14:41:28 tony (Tony Parkhurst)
- X * fixed usage message
- X *
- X * Revision 1.11 91/02/06 14:38:10 14:38:10 tony (Tony Parkhurst)
- X * Added file input and output for MS-DOS.
- X *
- X * Revision 1.10 91/02/05 17:49:23 17:49:23 tony (Tony Parkhurst)
- X * Fixed problem with zero stripped input.
- X *
- X * Revision 1.9 91/02/05 16:11:39 16:11:39 tony (Tony Parkhurst)
- X * Removed delay code and bitfield stuff.
- X *
- X * Revision 1.8 91/02/05 11:04:53 11:04:53 tony (Tony Parkhurst)
- X * Added io delay stuff for triton.
- X *
- X * Revision 1.7 91/02/05 10:28:32 10:28:32 tony (Tony Parkhurst)
- X * Fix for someone specifing ONLY mode 3.
- X *
- X * Revision 1.6 91/01/29 14:13:09 14:13:09 tony (Tony Parkhurst)
- X * Updated some comments.
- X *
- X * Revision 1.5 91/01/29 13:26:24 13:26:24 tony (Tony Parkhurst)
- X * Cleaned up, revamped a bit.
- X *
- X * Revision 1.4 89/11/09 15:59:16 15:59:16 tony (Tony Parkhurst)
- X * Fix for esc * r U coming after esc * r A.
- X *
- X * Revision 1.3 89/10/24 11:31:12 11:31:12 tony (Tony Parkhurst)
- X * Added parsing of <esc>*rC
- X *
- X * Revision 1.2 89/10/13 09:56:46 09:56:46 tony (Tony Parkhurst)
- X * Completely revamped by Greg G.
- X *
- X * Revision 1.1 89/06/15 13:57:46 13:57:46 tony (Tony Parkhurst)
- X * Initial revision
- X *
- X *
- X ***************************************************************************
- X */
- X
- Xstatic char *rcs_id="$Header: pclcomp.c,v 1.28 91/04/30 09:41:24 tony Exp $";
- X
- Xstatic char *rev_id="$Revision: 1.28 $";
- X
- Xstatic char *author="Copyright (c) 1991, Tony Parkhurst";
- X
- X/* This program takes a PCL graphics file and will try and
- X * optimize the compression.
- X */
- X
- X/*
- X * This program was first a filter by Dean to compress pcl graphics.
- X *
- X * This program now will do optimal compression using modes 0,1,2 and 3
- X *
- X * Also, this program will take compressed input.
- X *
- X * Input and output formats are standard pcl.
- X *
- X * Imaging files will be compressed too.
- X *
- X * pclcomp does not take advantage of Y-Offset for blank areas.
- X * This is because Y-Offset creates white areas, but we don't do enough
- X * parsing to determine what value "white" has. An application that
- X * can assume white values could make use of this sequence.
- X *
- X * pclcomp does not do any of the block compression modes (4-8).
- X *
- X * There are a few obvious inefficiencies that I will fix later.
- X *
- X * Speaking of mode 3, there is a possible problem because each of the
- X * output row storage areas are 2* size of what mode 0 would be. This
- X * is clearly sufficient for modes 1 and 2, but it may not be for mode
- X * 3. But I cannot think of a case in Mode 3 where this would be a problem.
- X *
- X * An additional enhancement would be to compare all the planes in a
- X * multi-plane file (color) and if nothing changed, using mode 3, just
- X * output a single <esc>*b0W.
- X */
- X
- X/*
- X * Usage: pclcomp [-v] [-0] [-1] [-2] [-3] [-z] [-n###] < infile > outfile
- X *
- X * Pclcomp will do graphics compression based on compression modes 0, 1, 2
- X * and 3. (Mode 0 is uncompressed). Pclcomp will accept all modes, and
- X * will attempt to optimize by selecting the best output mode for each
- X * row (or plane) of data. By default, pclcomp will use all 4 modes, but
- X * the user may restrict which output modes to use with the -0123 options.
- X * For example, to use pclcomp for output to a PaintJet which only knows
- X * modes 0 and 1 (the XL also understands modes 2 and 3), one would use:
- X *
- X * pclcomp -01 < infile > outfile
- X *
- X * Note: Mode 0 should always be allowed. None of the other modes is
- X * guaranteed to be better than mode 0 in all cases.
- X *
- X * The 'v' option tells the number of rows (planes) of data input and output
- X * in the different modes (to stderr).
- X *
- X * The 'z' option is useful for PaintJet files using only modes 0 and 1, it
- X * does zero "stripping" as the PaintJet will do zero "filling".
- X * NOTE: 'z' now means do NOT zerostrip.
- X *
- X * The 'n' option is to change the default number of pixels in a picture.
- X * The proper way to set the pixel width is with the source raster width
- X * sequence <esc*r#S>, but soo many applications just assume the default,
- X * which is different on different printers, so I am providing this
- X * command line option to set a new default. One could also change the
- X * DEFAULT constant below (make sure it is a multiple of 8). Currently
- X * it is set to 8" at 180 dpi (1440), but for 300 dpi, set it to 2400.
- X *
- X * default is now 2400 (for 300dpi ala LaserJet).
- X */
- X
- X#include <stdio.h>
- X#include <string.h>
- X
- X#ifdef MSDOS
- X#include <fcntl.h>
- X#endif
- X
- X
- X/* This flag is for code that uses bitfields for 68000 systems */
- X#define BITFIELDS 0
- X
- X#define Get_Character() getchar()
- X
- X#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) )
- X
- X#define TRUE 1
- X#define FALSE 0
- X
- X#define ESC 27
- X
- X#define DEFAULT 2400 /* default width in pixels (multiple of 8) */
- X
- X#define MAXMODES 4
- X#define MAXPLANES 8
- X#define MAXBYTES 60000 /* now mostly meaningless, just a big number */
- X
- Xunsigned char *seed_row[MAXPLANES];
- Xunsigned char *new_row;
- Xunsigned char *out_row[MAXMODES];
- Xunsigned int out_size[MAXMODES];
- X
- Xchar memflag = FALSE; /* set when memory has been allocated */
- X
- X
- Xchar mode0=FALSE,
- X mode1=FALSE,
- X mode2=FALSE,
- X mode3=FALSE;
- X
- Xunsigned char num_planes=1;
- Xunsigned char curr_plane=0;
- X
- Xchar imaging = FALSE; /* not imaging, so no lockout */
- X
- Xchar verbose = FALSE;
- X
- Xunsigned char inmode = 0; /* input compression mode */
- Xunsigned char outmode = 0; /* output compression mode */
- X
- Xunsigned int rasterwidth=DEFAULT/8; /* width of picture, in bytes */
- Xunsigned int rpix = DEFAULT; /* width of picture, in pixels */
- X
- Xunsigned char invert=FALSE; /* invert the data (obsolete) */
- X
- Xunsigned char zerostrip= TRUE; /* strip trailing zeros */
- X
- Xunsigned int inuse[4]={0,0,0,0}, outuse[4] = {0,0,0,0};
- X
- Xchar widthwarning = FALSE; /* for trucation warning */
- Xchar firstrow = TRUE; /* to prevent mode 3 from being first */
- X
- X
- Xstruct { /* this will hold the data for the */
- X unsigned char model; /* configuring of image processing */
- X unsigned char pix_mode;
- X unsigned char inx_bits;
- X unsigned char red;
- X unsigned char green;
- X unsigned char blue;
- X short wr;
- X short wg;
- X short wb;
- X short br;
- X short bg;
- X short bb;
- X} imdata;
- X
- Xextern unsigned char *malloc();
- X
- Xchar *filein = NULL, *fileout = NULL;
- X
- X/*
- X** These variables are for the new parser.
- X** The new parser handles more sequences, and also deals with combined
- X** escape sequences better.
- X*/
- X
- Xint parameter;
- Xint group_char;
- Xint terminator;
- Xint old_terminator;
- Xint value;
- Xint frac;
- Xint scanf_count;
- Xchar in_sequence = FALSE;
- Xchar pass_seq;
- Xchar plus_sign; /* for relative values */
- X
- X
- X/* dummy buffer */
- Xchar buf[BUFSIZ];
- X
- X/*
- X** If the printer is a DeskJet, then we must handle <esc>*rB differently
- X** Option '-d' will turn on this mode.
- X*/
- X
- Xchar deskjet = FALSE;
- X
- X
- X/*
- X** Many drivers it seems put <esc>*rB<esc>*rA between each and every row
- X** of data. This defeats compression mode 3 on a DeskJet, and also
- X** makes the PaintJet (not XL) quite slow. This next flag "-s" on the
- X** command line, will attempt to do a reasonable job of stripping
- X** out the excess commands.
- X**
- X** The in_graphics flag will be used to strip unwanted control chars from
- X** the file.
- X*/
- X
- Xchar strip_seq = FALSE;
- Xchar in_graphics = FALSE;
- X
- X
- X/*
- X** Just for certain special cases, it would be nice to append an <esc>E reset
- X** to the end of the job. Specify with "-r".
- X*/
- X
- Xchar reset_seq = FALSE;
- X
- X
- Xchar *progname; /* to hold the program name for verbose */
- X
- X
- X
- X/*
- X**
- X** Main program.
- X**
- X*/
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X int c,j;
- X extern char *optarg;
- X extern int optind;
- X
- X progname = argv[0];
- X
- X#ifdef MSDOS
- X setmode(fileno(stdin), O_BINARY); /* Place stdin and stdout in */
- X setmode(fileno(stdout), O_BINARY); /* binary mode. (Mike Slomin)*/
- X#endif
- X
- X /* parse up the args here */
- X
- X while ((c = getopt(argc, argv, "0123drsvzn:i:o:s")) != EOF )
- X switch(c){
- X case '0':
- X mode0++;
- X break;
- X case '1':
- X mode1++;
- X break;
- X case '2':
- X mode2++;
- X break;
- X case '3':
- X mode3++;
- X break;
- X case 'd':
- X deskjet++;
- X break;
- X case 'r':
- X reset_seq++;
- X break;
- X case 's':
- X strip_seq++;
- X break;
- X case 'v':
- X verbose++;
- X break;
- X case 'z':
- X zerostrip = FALSE;
- X break;
- X case 'n':
- X rpix = atoi(optarg); /* new default */
- X rasterwidth = (rpix + 7) / 8; /* round up */
- X break;
- X
- X case 'i':
- X filein = optarg;
- X break;
- X case 'o':
- X fileout = optarg;
- X break;
- X
- X case '?':
- X default:
- X fprintf(stderr, "Usage: %s [-0123drsvz] [-n###] [infile [outfile]]\n",
- X argv[0]);
- X exit(-1);
- X };
- X
- X if ( verbose )
- X {
- X fprintf(stderr, "%s: %s\n", argv[0], rev_id);
- X }
- X
- X
- X if ( ! ( mode0 || mode1 || mode2 || mode3) ) /* any modes on? */
- X mode0 = mode1 = mode2 = mode3 = TRUE; /* all modes by default */
- X
- X /*
- X ** Check to see if any file args were given on the command line.
- X ** Ones that were not preceded by a "-i" or "-o".
- X */
- X
- X if ( filein == NULL && optind < argc && argv[optind] != NULL )
- X filein = argv[optind++];
- X
- X if ( fileout == NULL && optind < argc && argv[optind] != NULL )
- X fileout = argv[optind++];
- X
- X /*
- X ** Now open files for stdin and stdout if provided by the user.
- X */
- X
- X if ( filein != NULL ) /* new input file */
- X
- X if ( freopen( filein, "rb", stdin ) == NULL )
- X {
- X fprintf(stderr,"Unable to open %s for input.\n",filein);
- X exit(-42);
- X }
- X
- X if ( fileout != NULL ) /* new output file */
- X
- X if ( freopen( fileout, "wb", stdout ) == NULL )
- X {
- X fprintf(stderr, "Unable to open %s for output.\n",
- X fileout);
- X exit(-43);
- X }
- X
- X
- X /*
- X ** This is the pcl input parsing loop.
- X */
- X
- X while( ( c = getchar() ) != EOF )
- X {
- X
- X /* Ignore all chars until an escape char */
- X
- X /*
- X ** If we are in graphics, toss it if strip_seq is set.
- X */
- X
- X if ( c != ESC )
- X {
- X if ( !strip_seq || !in_graphics )
- X putchar(c); /* pass it thru */
- X
- X continue; /* pop to the top of the loop */
- X }
- X
- X /*
- X ** Now we have an escape sequence, get the parameter char.
- X */
- X
- X parameter = getchar();
- X
- X if ( parameter == EOF ) /* oops */
- X {
- X putchar ( ESC );
- X fprintf(stderr, "Warning: File ended with <esc>.\n");
- X break; /* unexpected end of input */
- X }
- X
- X /*
- X ** Now check to see if it is a two character sequence.
- X */
- X
- X if ( parameter >= '0' && parameter <= '~' )
- X {
- X putchar ( ESC );
- X putchar ( parameter ); /* pass it thru */
- X
- X /*
- X ** If the second character is an E, then we
- X ** and the printer do a reset.
- X */
- X
- X if ( parameter == 'E' )
- X {
- X free_mem();
- X curr_plane = 0;
- X num_planes = 1;
- X imaging = FALSE;
- X inmode = 0;
- X outmode = 0;
- X in_graphics = FALSE;
- X
- X /* can't do this if user gave value with -n.
- X rasterwidth = DEFAULT/8;
- X rpix = DEFAULT;
- X */
- X }
- X
- X continue; /* return to the top */
- X }
- X
- X /*
- X ** Now check to make sure that the parameter character is
- X ** within range.
- X */
- X
- X if ( parameter < '!' || parameter > '/' )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X
- X fprintf(stderr, "Warning: Invalid escape sequence.\n");
- X
- X continue;
- X }
- X
- X /*
- X ** We are only interested in certain parameters, so pass
- X ** the rest of the sequences.
- X */
- X
- X /*
- X ** For the moment, we are only interested in '*' (graphics)
- X ** '(' and ')' (downloads). Although we do not do anything
- X ** with downloads, we need to pass the binary data thru
- X ** untouched.
- X ** Also, '&' is handled too.
- X */
- X
- X if ( parameter != '*' && parameter != '('
- X && parameter != ')' && parameter != '&' )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X Flush_To_Term(); /* flush rest of seq. */
- X continue;
- X }
- X
- X
- X /*
- X ** Parameter character is in range, look for a valid group char
- X */
- X
- X group_char = getchar();
- X
- X if ( group_char == EOF ) /* oops, ran out of input */
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X
- X fprintf(stderr, "Warning: Incomplete escape sequence.\n");
- X break;
- X }
- X
- X /*
- X ** See if in proper range. If it isn't, it is not an error
- X ** because the group character is optional for some sequences.
- X ** For the moment, we are not interested in those sequences,
- X ** so pass them thru.
- X */
- X
- X if ( group_char < '`' || group_char > '~' )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group_char );
- X if ( group_char < '@' || group_char > '^' )
- X Flush_To_Term(); /* pass rest of seq. */
- X continue;
- X }
- X
- X /*
- X ** Now we have a valid group character, decide if we want
- X ** to deal with this escape sequence.
- X **
- X ** Sequences we want do deal with include:
- X **
- X ** <esc>*r ** graphics
- X ** <esc>*b ** graphics
- X ** <esc>*v ** graphics
- X **
- X ** Sequences we must pass thru binary data:
- X **
- X ** <esc>*c ** pattern
- X ** <esc>*t ** obsolete
- X ** <esc>(f ** download char set
- X ** <esc>(s ** download char
- X ** <esc>)s ** download font
- X ** <esc>&a ** logical page
- X ** <esc>&l ** obsolete
- X **
- X */
- X
- X if ( ( parameter == '*'
- X && group_char != 'r' && group_char != 'b'
- X && group_char != 'v' && group_char != 'c'
- X && group_char != 't' )
- X || ( parameter == '&'
- X && group_char != 'a' && group_char != 'l' )
- X || ( parameter == '('
- X && group_char != 'f' && group_char != 's' )
- X || ( parameter == ')' && group_char != 's' ) )
- X {
- X /*
- X ** Definately not interested in the sequence.
- X */
- X
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group_char );
- X Flush_To_Term();
- X continue;
- X }
- X
- X /*
- X ** Now set up a pass thru flag so we can ignore the entire
- X ** sequences of some of these.
- X */
- X
- X if ( parameter != '*' )
- X pass_seq = TRUE;
- X else if ( group_char == 'c' || group_char == 't' )
- X pass_seq = TRUE;
- X else
- X pass_seq = FALSE;
- X
- X
- X /*
- X ** Now we have a sequence that we are definately interested in.
- X **
- X ** Get the value field and terminator, and loop until final
- X ** terminator is found.
- X */
- X
- X do
- X {
- X /* first see if the value has a plus sign */
- X
- X scanf_count = scanf(" + %d", &value );
- X
- X if ( scanf_count == 1 )
- X
- X plus_sign = TRUE;
- X else
- X {
- X plus_sign = FALSE;
- X
- X scanf_count = scanf(" %d", &value );
- X
- X if ( scanf_count == 0 )
- X value = 0; /* by default */
- X }
- X
- X terminator = getchar();
- X
- X /*
- X ** check to see if a fractional parameter was passed.
- X */
- X
- X frac = 0; /* in case no fraction */
- X
- X if ( terminator == '.' )
- X {
- X /*
- X ** Need to get fractional part.
- X **
- X ** This will not work properly if the
- X ** fraction is < .1 (i.e. a leading 0 is
- X ** present). For example, the value
- X ** 14.05 for point size, which would get
- X ** rounded to 14.00 for scalable fonts,
- X ** would get passed thru as 14.5 which is
- X ** rounded to 14.5. This is unlikely to
- X ** happen as the 14.05 case is rare, but
- X ** it is valid PCL, so I will fix this
- X ** in the future.
- X */
- X
- X if ( scanf("%d", &frac) != 1 )
- X {
- X frac = 0; /* no frac? */
- X }
- X
- X /*
- X ** Now get the real terminator.
- X */
- X
- X terminator = getchar();
- X }
- X
- X
- X if ( terminator == EOF ) /* barf */
- X {
- X fprintf(stderr, "Warning: Incomplete sequence at end of file.\n");
- X break;
- X }
- X
- X /*
- X ** If the pass_seq flag is set, then just pass
- X ** it thru to stdout until a 'W' is found.
- X */
- X
- X if ( pass_seq )
- X {
- X /*
- X ** If not in sequence, then we output esc
- X ** otherwise, output the saved terminator.
- X */
- X
- X if ( !in_sequence )
- X {
- X in_sequence = TRUE;
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group_char );
- X } else
- X {
- X putchar ( old_terminator );
- X }
- X
- X /* now pass the value */
- X
- X if ( plus_sign )
- X putchar('+');
- X
- X if ( scanf_count ) /* there was a value */
- X printf("%0d", value);
- X
- X /* need to output the fractional part */
- X
- X if ( frac )
- X printf(".%0d", frac);
- X
- X /*
- X ** We save the terminator, because we may
- X ** need to change it to upper case.
- X */
- X
- X old_terminator = terminator;
- X
- X /* if binary data, pass it thru */
- X
- X if ( terminator == 'W' ) /* aha */
- X {
- X putchar ( terminator );
- X in_sequence = FALSE; /* terminates */
- X Flush_Bytes ( value ); /* pass data */
- X }
- X
- X continue;
- X }
- X
- X /*
- X ** Ok, this is a sequence we want to pay attention to.
- X **
- X ** Do_Graphics returns TRUE if we need to pass seq.
- X **
- X ** Note: Do_Graphics modifies the parser vars such
- X ** as in_sequence. This is because it may
- X ** have to output stuff directly.
- X */
- X
- X if ( Do_Graphics ( group_char, value, terminator ) )
- X {
- X /*
- X ** If not in sequence, then we output esc
- X ** otherwise, output the saved terminator.
- X */
- X
- X if ( !in_sequence )
- X {
- X in_sequence = TRUE;
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group_char );
- X } else
- X {
- X putchar ( old_terminator );
- X }
- X
- X /* now pass the value */
- X
- X if ( plus_sign )
- X putchar('+');
- X
- X if ( scanf_count ) /* there was a value */
- X printf("%0d", value);
- X
- X /* need to output the fractional part */
- X
- X if ( frac )
- X printf(".%0d", frac);
- X
- X /*
- X ** We save the terminator, because we may
- X ** need to change it to upper case.
- X */
- X
- X old_terminator = terminator;
- X }
- X
- X } while ( terminator >= '`' && terminator <= '~' );
- X
- X /*
- X ** The oppsite test (above) may be more appropriate. That is,
- X ** !(terminator >= '@' && terminator <= '^').
- X */
- X
- X /*
- X ** If we were in a sequence, then we must terminate it.
- X ** If it was lower case, then it must be uppered.
- X */
- X
- X if ( in_sequence )
- X {
- X putchar ( terminator & 0xdf ); /* a ==> A */
- X in_sequence = FALSE;
- X }
- X }
- X
- X
- X /*
- X ** If the user wants a reset, give him one.
- X */
- X
- X if ( reset_seq )
- X {
- X putchar ( ESC );
- X putchar ( 'E' );
- X }
- X
- X
- X /*
- X ** Finished up, so print stats and close output file.
- X */
- X
- X fclose(stdout);
- X
- X
- X if ( verbose )
- X {
- X for(j = 0; j < 4; j++)
- X fprintf(stderr,"Rows in mode %1d: %d\n", j, inuse[j]);
- X for(j = 0; j < 4; j++)
- X fprintf(stderr,"Rows out mode %1d: %d\n", j, outuse[j]);
- X }
- X
- X exit(0);
- X}
- X
- X
- X/*
- X** Do_Graphics() takes the graphics escape sequence and performs the
- X** necessary functions.
- X** TRUE is returned if the escape sequence needs to be passed to the output.
- X*/
- X
- Xint Do_Graphics( group, num, terminator )
- Xint group, num, terminator;
- X{
- X
- X /* first look at vW */
- X
- X if ( group == 'v' )
- X
- X if ( terminator != 'W' )
- X
- X return ( TRUE ); /* pass it thru */
- X else
- X {
- X if ( !in_sequence )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group );
- X } else
- X putchar ( old_terminator );
- X
- X in_sequence = FALSE; /* terminating */
- X
- X printf("%0d", num);
- X putchar ( terminator );
- X
- X free_mem(); /* reset memory */
- X
- X imaging++;
- X
- X fread(&imdata, MIN(num, 18), 1, stdin);
- X fwrite(&imdata, MIN(num, 18), 1, stdout);
- X
- X num -= MIN(num, 18);
- X
- X /* copy rest of unknown data */
- X
- X if ( num > 0 )
- X Flush_Bytes(num);
- X
- X
- X switch(imdata.pix_mode){
- X case 0x00:
- X rasterwidth = (rpix + 7)/8;
- X num_planes = imdata.inx_bits;
- X break;
- X case 0x01:
- X rasterwidth = rpix*imdata.inx_bits/8;
- X break;
- X case 0x02:
- X rasterwidth = (rpix + 7)/8;
- X num_planes =imdata.red + imdata.green +
- X imdata.blue;
- X break;
- X case 0x03:
- X rasterwidth = (imdata.red +
- X imdata.green +
- X imdata.blue)*rpix/8;
- X break;
- X }
- X
- X return ( FALSE );
- X }
- X
- X /*
- X ** Now deal with <esc>*r stuff
- X */
- X
- X if ( group == 'r' )
- X {
- X switch ( terminator )
- X {
- X case 'A':
- X case 'a':
- X
- X /* in graphics mode, may do stripping */
- X in_graphics = TRUE;
- X
- X /* if user wants to strip redundant seq */
- X if ( strip_seq && memflag )
- X return( FALSE );
- X
- X curr_plane=0;
- X zero_seeds(); /* may allocate mem */
- X break;
- X
- X case 'C':
- X case 'c':
- X
- X /* not in graphics disable code strip */
- X
- X in_graphics = FALSE;
- X
- X if ( strip_seq )
- X return( FALSE );
- X
- X inmode = 0;
- X outmode = 0;
- X
- X free_mem();
- X curr_plane=0;
- X break;
- X
- X case 'B':
- X case 'b':
- X
- X /* not in graphics disable code strip */
- X
- X in_graphics = FALSE;
- X
- X if ( strip_seq )
- X return( FALSE );
- X
- X if ( deskjet ) /* B resets modes on DJ */
- X {
- X inmode = 0;
- X outmode = 0;
- X }
- X free_mem();
- X curr_plane=0;
- X break;
- X
- X case 'S':
- X case 's':
- X
- X /* free mem in case widths changed */
- X free_mem();
- X
- X rpix = num;
- X
- X if (imaging){
- X switch(imdata.pix_mode)
- X {
- X case 0x00:
- X rasterwidth=(rpix+7)/8;
- X break;
- X case 0x01:
- X rasterwidth =
- X rpix*imdata.inx_bits/8;
- X break;
- X case 0x02:
- X rasterwidth=(rpix+7)/8;
- X break;
- X case 0x03:
- X rasterwidth =
- X (imdata.red
- X + imdata.green
- X + imdata.blue)*rpix/8;
- X break;
- X }
- X } else
- X rasterwidth = (num + 7) / 8;
- X break;
- X
- X case 'T':
- X case 't':
- X break;
- X
- X case 'U':
- X case 'u':
- X curr_plane=0;
- X free_mem(); /* if ESC*rA came first */
- X num_planes = num;
- X imaging = FALSE; /* goes off */
- X break;
- X
- X default:
- X break;
- X }
- X
- X return ( TRUE ); /* pass sequence on */
- X
- X } /* group r */
- X
- X /*
- X ** Last and final group 'b'. All the graphics data comes thru here.
- X */
- X
- X
- X switch ( terminator )
- X {
- X case 'm':
- X case 'M':
- X inmode = num;
- X return ( FALSE ); /* we do NOT pass this */
- X break;
- X
- X /*
- X ** <esc>*b#X is obsolete, don't bother with it.
- X ** If I did do something, then I would zero part of the
- X ** seed rows.
- X */
- X
- X case 'x':
- X case 'X':
- X break;
- X
- X case 'y':
- X case 'Y':
- X /* zero only if allocated */
- X if ( memflag )
- X zero_seeds();
- X break;
- X
- X case 'W':
- X if(!memflag)
- X zero_seeds(); /* get memory */
- X
- X /* fire up sequence */
- X
- X if ( !in_sequence )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group );
- X } else
- X putchar ( old_terminator );
- X
- X in_sequence = FALSE; /* terminating */
- X
- X if(curr_plane < num_planes)
- X {
- X
- X Process(num, 'W');
- X
- X if ( curr_plane + 1 < num_planes )
- X {
- X /* now we have a problem */
- X zero_upper(curr_plane + 1);
- X }
- X } else
- X Process_extra(num,'W');
- X
- X curr_plane=0;
- X
- X return ( FALSE );
- X
- X break;
- X
- X case 'V':
- X if(!memflag)
- X zero_seeds(); /* get memory */
- X
- X /*
- X ** If curr_plane is the last plane, this should
- X ** be a 'W', not a 'V'. I could change it,
- X ** then I would fix Process_extra() to not output
- X ** anything as the 'W' was already sent.
- X */
- X
- X if( curr_plane < num_planes )
- X {
- X /* fire up sequence */
- X
- X if ( !in_sequence )
- X {
- X putchar ( ESC );
- X putchar ( parameter );
- X putchar ( group );
- X } else
- X putchar ( old_terminator );
- X
- X in_sequence = FALSE; /* terminating */
- X
- X
- X Process(num, 'V');
- X curr_plane++;
- X } else
- X Process_extra(num,'V');
- X
- X return ( FALSE );
- X
- X break;
- X
- X default:
- X break;
- X }
- X
- X return ( TRUE ); /* pass sequence */
- X}
- X
- X
- X
- X/*
- X** Flush_To_Term() simply passes thru input until a valid terminator
- X** character is found. This is for unwanted escape sequences.
- X*/
- X
- XFlush_To_Term()
- X{
- X int c;
- X
- X do
- X {
- X c = getchar();
- X
- X if ( c == EOF ) /* this is a problem */
- X return;
- X
- X putchar ( c );
- X
- X } while ( c < '@' || c > '^' );
- X}
- X
- X
- X/*
- X** Flush_Bytes() simply transfers so many bytes directly from input to output.
- X** This is used to pass thru binary data that we are not interested in so that
- X** it will not confuse the parser. I.e. downloads.
- X*/
- X
- XFlush_Bytes( num )
- Xunsigned int num;
- X{
- X int bnum;
- X
- X while ( num > 0 )
- X {
- X bnum = MIN ( BUFSIZ, num );
- X
- X fread( buf, 1, bnum, stdin );
- X
- X if ( fwrite( buf, 1, bnum, stdout ) < bnum )
- X
- X /* check for error and exit */
- X
- X if ( ferror(stdout) )
- X {
- X perror("Output error");
- X exit(-2);
- X }
- X
- X num -= bnum;
- X }
- X}
- X
- X
- X
- X
- X/*----------------------------------------*/
- X
- X/*
- X** Zero_seeds() will allocate and initialize memory.
- X** If memory has already been allocated, then it will just initialize it.
- X*/
- X
- X
- Xzero_seeds()
- X{
- X int r;
- X
- X /* first allocate and init seed_rows for number of planes. */
- X
- X for ( r = 0; r < num_planes ; r++)
- X {
- X if(!memflag)
- X {
- X seed_row[r] = (unsigned char *) malloc(rasterwidth);
- X
- X if ( seed_row[r] == NULL )
- X {
- X fprintf(stderr, "Out of memory.\n");
- X exit(-3);
- X }
- X }
- X
- X /* zero seeds for mode 3 */
- X
- X memset(seed_row[r], 0, rasterwidth);
- X }
- X
- X
- X if(!memflag)
- X {
- X new_row = (unsigned char *) malloc(rasterwidth);
- X
- X if ( new_row == NULL )
- X {
- X fprintf(stderr, "Out of memory.\n");
- X exit(-3);
- X }
- X
- X for(r=0; r<MAXMODES; r++)
- X {
- X /* 2 * width is needed for modes 1, 2 and 3 */
- X
- X out_row[r] = (unsigned char *) malloc(2 * rasterwidth);
- X
- X if ( out_row[r] == NULL )
- X {
- X fprintf(stderr, "Out of memory.\n");
- X exit(-3);
- X }
- X }
- X
- X }
- X
- X memset(new_row, 0, rasterwidth);
- X
- X memflag = TRUE; /* memory is in place */
- X}
- X
- X
- X/* this routine if for incomplete transfers of data */
- X
- Xzero_upper(plane)
- Xint plane;
- X{
- X int i;
- X
- X /* assume memory already present */
- X
- X for ( i = plane; i < num_planes; i++)
- X memset(seed_row[i], 0, rasterwidth);
- X}
- X
- X
- XProcess(inbytes, terminator)
- Xint inbytes, terminator;
- X{
- X
- X int insize;
- X int minmode = 0;
- X
- X inuse[inmode]++;
- X
- X switch ( inmode ) {
- X
- X case 0:
- X if ( !widthwarning && inbytes > rasterwidth )
- X {
- X /* This is likely to result in data truncation. */
- X widthwarning = TRUE;
- X fprintf(stderr,"Warning: Input pixel width exceeds expected width.\n");
- X }
- X
- X insize = Mode_0_Graphics(inbytes,rasterwidth,new_row,invert);
- X break;
- X case 1:
- X insize = Mode_1_Graphics(inbytes,rasterwidth,new_row,invert);
- X break;
- X case 2:
- X insize = Mode_2_Graphics(inbytes,rasterwidth,new_row,invert);
- X break;
- X case 3:
- X memcpy(new_row, seed_row[curr_plane], rasterwidth);
- X insize = Mode_3_Graphics(inbytes,rasterwidth,new_row,invert);
- X break;
- X
- X default: /* unknown mode? */
- X
- X /* Don't know what to do about seed rows, pass stuff thru */
- X
- X fprintf(stderr, "%s: Unsupported compression mode %d.\n",
- X progname, inmode );
- X
- X ChangeMode(inmode); /* go to that mode */
- X
- X /* <esc>*b has already been output */
- X
- X printf("%1d%c", inbytes, terminator);
- X
- X Flush_Bytes( inbytes );
- X
- X firstrow = TRUE; /* pop it out of mode 3 */
- X
- X /* Go ahead and clear the seed rows if present */
- X if ( memflag )
- X zero_seeds();
- X
- X return;
- X
- X }
- X
- X
- X /*
- X **
- X */
- X
- X if ( mode0 )
- X /* actually, this is redundant since new_row is mode 0 */
- X out_size[0] = Output_0( new_row, out_row[0], rasterwidth );
- X else
- X out_size[0] = MAXBYTES+1;
- X
- X if ( mode1 )
- X out_size[1] = Output_1( new_row, out_row[1], rasterwidth );
- X else
- X out_size[1] = MAXBYTES+1;
- X
- X if ( mode2 )
- X out_size[2] = Output_2( new_row, out_row[2], rasterwidth );
- X else
- X out_size[2] = MAXBYTES+1;
- X
- X if ( mode3 )
- X out_size[3] = Output_3( seed_row[curr_plane], new_row, out_row[3], rasterwidth );
- X else
- X out_size[3] = MAXBYTES+1;
- X
- X
- X /*
- X ** Now determine which mode will give the best output. Note that it
- X ** takes 5 bytes to change modes, so we penalize all modes that are
- X ** not the current output by 5 bytes. This is to discourage changing
- X ** unless the benifit is worth it. The exception to this rule is
- X ** mode 3. We want to encourage going to mode 3 because of the seed
- X ** row behaviour. That is, if we have a simple picture that does
- X ** not change much, and say each of the sizes for modes 1 and 2 always
- X ** comes out to 4 bytes of data, then if we add 5 to mode 3 each time,
- X ** it would never get selected. But, we remove the penalty, and if
- X ** mode 3 is selected (0 bytes of data needed for mode 3), then each
- X ** succesive row only needs 0 bytes of data. For a 300 dpi A size
- X ** picture with 3 data planes, this could be a savings of 37k bytes.
- X */
- X
- X /*
- X ** With the new parser, the output to change modes is now only
- X ** 2 bytes, since it gets combined with the *b#W sequence.
- X ** So, I decided to ignore the switching penalty.
- X */
- X
- X /*
- X ** Due to a possible bug in PaintJet XL, don't allow mode 3 to be
- X ** selected for the first row of output. But do allow it if the
- X ** user has no other mode selected.
- X */
- X
- X if ( firstrow && (mode0 || mode1 || mode2) )
- X {
- X out_size[3] = MAXBYTES+1; /* disable mode 3 for now */
- X
- X if ( terminator == 'W' ) /* last plane? */
- X firstrow = FALSE; /* no longer first row */
- X }
- X
- X
- X minmode = 3;
- X
- X if ( out_size[2] < out_size[minmode] )
- X minmode = 2;
- X
- X if ( out_size[1] < out_size[minmode] )
- X minmode = 1;
- X
- X if ( out_size[0] < out_size[minmode] )
- X minmode = 0;
- X
- X
- X /* I may remove this sometime */
- X if ( minmode != outmode )
- X if ( out_size[minmode] == out_size[outmode] )
- X minmode = outmode;
- X
- X
- X outuse[minmode]++;
- X
- X if ( outmode != minmode )
- X ChangeMode( minmode );
- X
- X /* <esc>*b has already been output */
- X
- X printf("%1d%c", out_size[minmode], terminator);
- X
- X if ( fwrite( out_row[minmode], 1, out_size[minmode], stdout) <
- X out_size[minmode] )
- X
- X /* check for error and exit */
- X
- X if ( ferror(stdout) )
- X {
- X perror("Output error");
- X exit(-2);
- X }
- X
- X
- X memcpy(seed_row[curr_plane], new_row, rasterwidth);
- X
- X}
- X
- XProcess_extra(bytes, terminator)
- Xint bytes;
- Xchar terminator;
- X{
- X int i;
- X
- X /* toss any excess data */
- X
- X for(i = 0; i < bytes; i++)
- X getchar();
- X
- X /* last plane? force move down to next row */
- X
- X if(terminator == 'W')
- X {
- X /* <esc>*b has already been output */
- X printf("0W");
- X
- X firstrow = FALSE; /* not on first row anymore */
- X
- X }
- X
- X}
- X
- XChangeMode(newmode)
- Xint newmode;
- X{
- X /*
- X ** <esc>*b have already been output.
- X ** terminator is 'm' instead of 'M' since will be followed by 'W'
- X */
- X printf("%1dm", newmode);
- X outmode = newmode;
- X}
- X
- X
- X/* these decoders came from graphics.c in the gp parser */
- X
- X
- X/* $PAGE$ */
- X/*-----------------------------------------------------------------------*\
- X | |
- X | Function Name: Mode_0_Graphics |
- X | |
- X | Description: |
- X | |
- X | This is the routine that handles a Mode 0 graphics block transfer |
- X | to the Formatter Module. |
- X | |
- X\*-----------------------------------------------------------------------*/
- X
- X/* FUNCTION */
- X
- XMode_0_Graphics(input_bytes, output_bytes, address, invert)
- X
- Xunsigned int
- X input_bytes, /* Count of bytes to be read. */
- X output_bytes; /* Count of bytes to be stored. */
- X
- Xunsigned char
- X *address; /* Pointer to where to store bytes. */
- X
- Xunsigned char /* Boolean to request data inversion */
- X invert;
- X
- X{
- X /* LOCAL VARIABLES */
- X
- X unsigned char
- X *store_ptr; /* Pointer to where to store the byte. */
- X
- X unsigned int
- X read_bytes, /* Local copy of input_bytes. */
- X write_bytes; /* Local copy of output_bytes. */
- X
- X /* CODE */
- X
- X /* Initialize the local variables. */
- X
- X read_bytes = input_bytes;
- X write_bytes = output_bytes;
- X store_ptr = address;
- X
- X
- X /* transfer the lesser of available bytes or available room */
- X
- X if (invert)
- X Inv_Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
- X else
- X Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
- X
- X /* now zero fill or throw excess data away */
- X
- X if ( read_bytes > write_bytes )
- X Discard_Block(read_bytes - write_bytes); /* throw excess */
- X else {
- X store_ptr += read_bytes; /* adjust pointer */
- X write_bytes -= read_bytes; /* zero fill count */
- X
- X memset(store_ptr, 0, write_bytes);
- X }
- X
- X return ( input_bytes );
- X}
- X
- X/* $PAGE$ */
- X/*-----------------------------------------------------------------------*\
- X | |
- X | Function Name: Mode_1_Graphics |
- X | |
- X | Description: |
- X | |
- X | This is the routine that handles a Mode 1 graphics block transfer |
- X | to the Formatter Module. Mode 1 graphics is a compacted mode. |
- X | The data in Mode 1 is in pairs. The first byte is a replicate |
- X | count and the second byte is the data. The data byte is stored |
- X | then replicated the replicate count. Therefore a replicate count |
- X | of 0 means the data byte is stored once. The input byte count |
- X | must be an even amount for the data to be in byte pairs. |
- X | |
- X\*-----------------------------------------------------------------------*/
- X
- X/* FUNCTION */
- X
- XMode_1_Graphics(input_bytes, output_bytes, address, invert)
- X
- Xunsigned int
- X input_bytes, /* Count of bytes to be read. */
- X output_bytes; /* Count of bytes to be stored. */
- X
- Xunsigned char
- X *address; /* Pointer to where to store bytes. */
- X
- Xunsigned char /* Boolean to request data inversion */
- X invert;
- X
- X{
- X /* LOCAL VARIABLES */
- X
- X unsigned char
- X *store_ptr, /* Pointer to where to store the byte. */
- X input_char; /* Byte to be replicated. */
- X
- X unsigned int
- X read_bytes, /* Local copy of input_bytes. */
- X write_bytes; /* Local copy of output_bytes. */
- X
- X int
- X replicate_count; /* Number of times to replicate data. */
- X
- X /* CODE */
- X
- X /* Initialize the local variables. */
- X
- X read_bytes = input_bytes;
- X write_bytes = output_bytes;
- X store_ptr = address;
- X
- X /* Check for an even input count. */
- X
- X if ((read_bytes % 2) == 0)
- X {
- X /* Even so input data is in pairs as required. So store the data. */
- X
- X while ((read_bytes != 0) && (write_bytes != 0))
- X {
- X /* First get the replicate count and the byte to store. */
- X
- X replicate_count = (unsigned char) Get_Character();
- X input_char = (invert ? ~Get_Character() : Get_Character());
- X read_bytes -= 2;
- X
- X /* Since write_bytes was 0 there is room to store the byte. */
- X
- X *store_ptr++ = input_char;
- X write_bytes--;
- X
- X /* Now make sure there is room for the replicated data. */
- X
- X if (replicate_count > write_bytes)
- X {
- X /* Too much so limit to the room available. */
- X
- X replicate_count = write_bytes;
- X }
- X
- X /* Update the amount to be written. */
- X
- X write_bytes -= replicate_count;
- X
- X /* Then replicate it. */
- X
- X while (replicate_count != 0)
- X {
- X /* Store the byte the decrement the count. */
- X
- X *store_ptr++ = input_char;
- X
- X replicate_count--;
- X }
- X }
- X
- X }
- X /* Discard any left over input. */
- X /* OR */
- X /* Discard all of the input data as odd byte count. */
- X
- X Discard_Block(read_bytes);
- X
- X read_bytes = store_ptr - address; /* how much was done? */
- X
- X /* zero fill if needed */
- X memset(store_ptr, 0, write_bytes);
- X
- X return(read_bytes);
- X}
- X
- X/* $PAGE$ */
- X/*-----------------------------------------------------------------------*\
- X | |
- X | Function Name: Mode_2_Graphics |
- X | |
- X | Description: |
- X | |
- X | This is the routine that handles a Mode 2 graphics block transfer |
- X | to the Formatter Module. Mode 2 graphics is a compacted mode. |
- X | The data in Mode 2 is of one of two types. The first type is a |
- X | class type and the second type is a data type. The class type is |
- X | a single byte which is a combination of replicate count and a sub |
- X | mode. There are two sub modes within mode 2, sub mode 0 and sub |
- X | mode 1. These sub modes are flagged by the MSB of the class type |
- X | byte. If the MSB = 0 then the replicate count is the value of the |
- X | class type byte. In sub mode 0 the replicate count ranges from 1 |
- X | to 127. In sub mode 0 the next byte and then the replicate count |
- X | of bytes are of the data type and stored. If the MSB = 1 then the |
- X | sub mode is 1 and the replicate count is the negative value of the |
- X | class type. In sub mode 1 the replicate count is stored in 2s |
- X | compliment form and ranges from -1 to -127. In sub mode 1 the |
- X | next byte is of the data type and is stored. That data byte is |
- X | then replicated and stored the replicate count. If the class type |
- X | byte is 128 then there is no data type byte. |
- X | |
- X\*-----------------------------------------------------------------------*/
- X
- X/* FUNCTION */
- X
- XMode_2_Graphics(input_bytes, output_bytes, address, invert)
- X
- Xunsigned int
- X input_bytes, /* Count of bytes to be read. */
- X output_bytes; /* Count of bytes to be stored. */
- X
- Xunsigned char
- X *address; /* Pointer to where to store bytes. */
- X
- Xunsigned char /* Boolean to request data inversion */
- X invert;
- X
- X{
- X /* LOCAL VARIABLES */
- X
- X unsigned char
- X *store_ptr, /* Pointer to where to store the byte. */
- X input_char, /* Byte to be replicated. */
- X sub_mode; /* Flag if sub mode is 0 or 1. */
- X
- X unsigned int
- X read_bytes, /* Local copy of input_bytes. */
- X write_bytes; /* Local copy of output_bytes. */
- X
- X int
- X replicate_count; /* Number of times to replicate data. */
- X
- X /* CODE */
- X
- X /* Initialize the local variables. */
- X
- X read_bytes = input_bytes;
- X write_bytes = output_bytes;
- X store_ptr = address;
- X
- X while ((read_bytes > 1) && (write_bytes != 0))
- X {
- X /* First get the class type byte and the first data type byte. */
- X
- X replicate_count = Get_Character();
- X
- X /* First check that this not an ignore class type. */
- X
- X if (replicate_count != 128)
- X {
- X /* Not ignore so get the data class byte. */
- X
- X input_char = (invert ? ~Get_Character() : Get_Character());
- X read_bytes -= 2;
- X
- X /* Since write_bytes wasn't 0 there is room to store the byte. */
- X
- X *store_ptr++ = input_char;
- X write_bytes--;
- X
- X /* Determine the sub mode. */
- X
- X if (replicate_count > 128)
- X {
- X /* Sub mode 1. */
- X
- X sub_mode = 1;
- X /* replicate count was unsigned char */
- X replicate_count = 256 - replicate_count;
- X }
- X else
- X {
- X /* Sub mode 0. */
- X
- X sub_mode = 0;
- X
- X /* See if there is enoungh input left for the data byte count. */
- X
- X if (replicate_count > read_bytes)
- X {
- X /* Too many data bytes so limit to the input left. */
- X
- X replicate_count = read_bytes;
- X }
- X }
- X
- X /* Now make sure there is room for the replicated data. */
- X
- X if (replicate_count > write_bytes)
- X {
- X /* Too much so limit to the room available. */
- X
- X replicate_count = write_bytes;
- X }
- X
- X /* Update the amount to be written. */
- X
- X write_bytes -= replicate_count;
- X
- X /* Then replicate it. */
- X
- X if (sub_mode == 0)
- X {
- X /* Sub mode 0 so get the replicate count of data bytes. */
- X
- X if (invert)
- X Inv_Transfer_Block(replicate_count, store_ptr);
- X else
- X Transfer_Block(replicate_count, store_ptr);
- X
- X read_bytes -= replicate_count;
- X
- X /* Find the last byte stored. */
- X
- X store_ptr += replicate_count;
- X }
- X else
- X {
- X /* Sub mode 1 so just duplicate the original byte. */
- X
- X while (replicate_count != 0)
- X {
- X /* Store the byte the decrement the count. */
- X
- X *store_ptr++ = input_char;
- X
- X replicate_count--;
- X }
- X }
- X }
- X else
- X {
- X /* Ignore class so don't get the data class byte. */
- X
- X read_bytes--;
- X }
- X }
- X
- X /* Now discard any left over input. */
- X
- X Discard_Block(read_bytes);
- X
- X read_bytes = store_ptr - address;
- X
- X /* zero fill if needed */
- X memset(store_ptr, 0, write_bytes);
- X
- X
- X return(read_bytes);
- X}
- X
- X/* $PAGE$ */
- X/*-----------------------------------------------------------------------*\
- X | |
- X | Function Name: Mode_3_Graphics |
- X | |
- X | Description: |
- X | |
- X | This is the routine that handles a Mode 3 graphics block transfer |
- X | to the Formatter Module. Mode 3 graphics is a compacted mode. |
- X | Mode 3 data is a difference from one row to the next. In order to |
- X | work, each row must be saved to be a seed for the next. This |
- X | mode is used in conjuction with other compaction modes when the |
- X | data remains fairly constant between pairs of rows. |
- X | The data is in the form: |
- X | <command byte>[<optional offset bytes>]<1 to 8 replacement bytes> |
- X | The command byte is in the form: |
- X | Bits 5-7: Number of bytes to replace (1 - 8) |
- X | Bits 0-4: Relative offset from last byte. |
- X | (If the offset is 31, then add the following bytes for offset |
- X | until an offset byte of less then 255 (but inclusive) |
- X | |
- X\*-----------------------------------------------------------------------*/
- X
- X/* FUNCTION */
- X
- XMode_3_Graphics(input_bytes, output_bytes, address, invert)
- X
- Xunsigned int
- X input_bytes, /* Count of bytes to be read. */
- X output_bytes; /* Count of bytes to be stored. */
- X
- Xunsigned char
- X *address; /* Pointer to where to store bytes. */
- X
- Xunsigned char /* Boolean to request data inversion */
- X invert;
- X
- X{
- X /* LOCAL VARIABLES */
- X
- X unsigned char
- X *store_ptr, /* Pointer to where to store the byte. */
- X input_char; /* Byte to be changed. */
- X
- X unsigned int
- X read_bytes, /* Local copy of input_bytes. */
- X write_bytes; /* Local copy of output_bytes. */
- X
- X unsigned int
- X replace, /* number of bytes to replace, 1-8 */
- X offset; /* relative offset */
- X
- X#if BITFIELDS
- X union comtype {
- X unsigned char comchar; /* command byte as char */
- X struct btype {
- X unsigned repcount:3; /* replace count 1-8 */
- X unsigned roff:5; /* relative offset 0-30 */
- X } bitf;
- X } command;
- X#else
- X unsigned char command;
- X#endif
- X
- X /* CODE */
- X
- X /* Initialize the local variables. */
- X
- X read_bytes = input_bytes;
- X write_bytes = output_bytes;
- X store_ptr = address;
- X
- X/* read_bytes has to be at least 2 to be valid */
- X
- X while ( read_bytes > 1 && write_bytes > 0 ){
- X
- X /* start by getting the command byte */
- X
- X read_bytes--;
- X
- X#if BITFIELDS
- X command.comchar = Get_Character();
- X
- X replace = command.bitf.repcount + 1; /* replace count 1-8 */
- X
- X offset = command.bitf.roff; /* offset 0-30, 31= extend */
- X#else
- X command = Get_Character();
- X replace = (command >> 5) + 1;
- X offset = command & 0x1f;
- X#endif
- X
- X store_ptr += offset;
- X write_bytes -= offset;
- X
- X if ( offset == 31 ) /* get more offsets */
- X do{
- X
- X offset = Get_Character();
- X
- X read_bytes--;
- X if ( read_bytes == 0 ) /* premature finish? */
- X return; /* no zero fill wih 3 */
- X
- X store_ptr += offset;
- X write_bytes -= offset;
- X
- X } while (offset == 255); /* 255 = keep going */
- X
- X /* now do the byte replacement */
- X
- X while ( replace-- && write_bytes > 0 && read_bytes > 0 ){
- X
- X *store_ptr++ = (invert ? ~Get_Character() : Get_Character() );
- X
- X read_bytes--;
- X write_bytes--;
- X }
- X }
- X
- X /* don't do any zero fill with mode 3 */
- X
- X /* discard any leftover input */
- X
- X Discard_Block(read_bytes);
- X
- X return( store_ptr - address );
- X}
- X
- X
- XDiscard_Block(count)
- Xunsigned int count;
- X{
- X while ( count-- )
- X getchar();
- X}
- X
- XTransfer_Block( count, dest )
- Xunsigned int count;
- Xunsigned char *dest;
- X{
- X fread(dest, 1, count, stdin);
- X}
- X
- X/* this doesn't invert at the moment */
- X
- XInv_Transfer_Block( count, dest )
- Xunsigned int count;
- Xunsigned char *dest;
- X{
- X fread(dest, 1, count, stdin);
- X}
- X
- X
- XOutput_0(src, dest, count)
- Xunsigned char *src, *dest;
- Xint count;
- X{
- X memcpy(dest, src, count);
- X
- X if ( zerostrip )
- X while ( count && dest[count-1] == 0 )
- X count--;
- X
- X return(count);
- X
- X}
- X
- XOutput_1(src, dest, count)
- Xunsigned char *src, *dest;
- Xregister int count;
- X{
- X unsigned char *optr = dest, *iptr;
- X int k,c;
- X
- X if ( zerostrip ) /* strip zeros */
- X {
- X iptr = src + count - 1; /* point to end of data */
- X
- X while ( count > 0 && *iptr-- == 0 ) /* hunt thru 0's */
- X count--;
- X }
- X
- X iptr = src;
- X
- X while ( count ){
- X
- X c = *iptr++; /* get value to work with */
- X count--;
- X
- X k = 0;
- X
- X while ( *iptr == c && k < 255 && count ){
- X k++;
- X iptr++;
- X count--;
- X }
- X
- X *optr++ = k; /* output repeat count */
- X *optr++ = c; /* output value */
- X }
- X
- X count = optr - dest; /* for return value */
- X
- X return ( count );
- X}
- X
- X
- XOutput_2(src, dest, count)
- Xunsigned char *src, *dest;
- Xregister int count;
- X{
- X unsigned char *optr = dest, *iptr;
- X int k,c;
- X unsigned char *tptr, *tptr1, *tptr2;
- X int tk,tc;
- X
- X
- X if ( zerostrip ) /* strip zeros */
- X {
- X iptr = src + count - 1; /* point to end of data */
- X
- X while ( count > 0 && *iptr-- == 0 ) /* hunt thru 0's */
- X count--;
- X }
- X
- X iptr = src;
- X
- X while ( count ){
- X
- X c = *iptr++; /* get value to work with */
- X count--;
- X
- X k = 0;
- X
- X while ( *iptr == c && k < 127 && count ){
- X k++;
- X iptr++;
- X count--;
- X }
- X
- X if ( k >= 1 ){
- X *optr++ = 256 - k; /* output repeat count */
- X *optr++ = c; /* output value */
- X } else {
- X /* a two byte replicate run will
- X * be sent as a repeated byte
- X * unless it is preceeded and
- X * and followed by a literal run,
- X * in which case it is merged
- X * into the run.
- X */
- X tk = 0;
- X tc = c;
- X tptr = iptr;
- X tptr1 = tptr;
- X tptr1++;
- X tptr2 = tptr1;
- X tptr2++;
- X
- X while ( tk < 128 && (count - tk) > 0 &&
- X ((*tptr != tc) || (*tptr == tc &&
- X (count - tk - 1) > 0 &&
- X *tptr1 != *tptr &&
- X *tptr2 != *tptr1))){
- X
- X tc = *tptr++;
- X tk++;
- X tptr1++;
- X tptr2++;
- X }
- X
- X if ( count && tk )
- X tk--;
- X
- X *optr++ = tk; /* output count */
- X *optr++ = c; /* output firstvalue */
- X
- X while ( tk-- > 0){
- X *optr++ = *iptr++;
- X count--;
- X }
- X
- X }
- X }
- X
- X count = optr - dest; /* for return value */
- X
- X return ( count );
- X}
- X
- XOutput_3(seed, new, dest, count)
- Xunsigned char *seed, *new, *dest;
- Xint count;
- X{
- X unsigned char *sptr=seed, *nptr=new, *dptr=dest;
- X int i,j;
- X
- X
- X#if BITFIELDS
- X union comtype {
- X unsigned char comchar; /* command byte as char */
- X struct btype {
- X unsigned repcount:3; /* replace count 1-8 */
- X unsigned roff:5; /* relative offset 0-30 */
- X } bitf;
- X } command;
- X#else
- X unsigned char command;
- X#endif
- X
- X while ( count > 0 ){
- X i = 0;
- X
- X /* find first diff */
- X while ( *sptr == *nptr && i < count ){
- X i++;
- X sptr++;
- X nptr++;
- X }
- X
- X if ( i >= count ) /* too far to find diff */
- X return(dptr - dest); /* bail */
- X
- X count -= i;
- X
- X /* now count how many bytes to change */
- X
- X for ( j = 1; j < 8; j++) /* j == 0 is already known */
- X if ( j > count || sptr[j] == nptr[j] )
- X break;
- X
- X j--; /* adjust */
- X
- X#if BITFIELDS
- X command.bitf.repcount = j; /* 0-7 ==> 1-8 */
- X
- X command.bitf.roff = MIN ( i, 31 );
- X
- X *dptr++ = command.comchar; /* output command */
- X#else
- X command = (j << 5);
- X command += MIN( i, 31 );
- X *dptr++ = command;
- X#endif
- X
- X if ( i == 31 )
- X *dptr++ = 0;
- X
- X i -= MIN (i, 31);
- X
- X while( i ){
- X *dptr++ = MIN ( i, 255 );
- X
- X if ( i == 255 )
- X *dptr++ = 0;
- X
- X i -= MIN ( i, 255 );
- X }
- X
- X while (j-- >= 0){
- X *dptr++ = *nptr++;
- X sptr++;
- X count--;
- X }
- X }
- X
- X return ( dptr - dest );
- X}
- X
- X
- X/*----------------------------------------------------------------------*\
- X * This is here in case <ESC>*rU is sent after <ESC>*r#A, in which case *
- X * we must deallocate the memory to provide for a different amount of *
- X * planes when graphics are sent. *
- X\*----------------------------------------------------------------------*/
- X
- Xfree_mem()
- X{
- X int r;
- X
- X
- X if ( !memflag )
- X return; /* no memory to free */
- X
- X free(new_row);
- X
- X for(r = MAXMODES -1; r >= 0; r--)
- X free(out_row[r]);
- X
- X for(r = num_planes - 1; r >= 0; r--)
- X free(seed_row[r]);
- X
- X memflag = FALSE;
- X}
- END_OF_FILE
- if test 52617 -ne `wc -c <'pclcomp.c'`; then
- echo shar: \"'pclcomp.c'\" unpacked with wrong size!
- fi
- # end of 'pclcomp.c'
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-